package com.openfarmanager.android.fragments;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.openfarmanager.android.App;
import com.openfarmanager.android.R;
import com.openfarmanager.android.adapters.FlatFileSystemAdapter;
import com.openfarmanager.android.controllers.FileSystemController;
import com.openfarmanager.android.core.AbstractCommand;
import com.openfarmanager.android.core.CancelableCommand;
import com.openfarmanager.android.core.Settings;
import com.openfarmanager.android.core.archive.ArchiveScanner;
import com.openfarmanager.android.core.archive.ArchiveUtils;
import com.openfarmanager.android.filesystem.FileProxy;
import com.openfarmanager.android.filesystem.FileSystemFile;
import com.openfarmanager.android.filesystem.FileSystemScanner;
import com.openfarmanager.android.filesystem.actions.*;
import com.openfarmanager.android.model.Bookmark;
import com.openfarmanager.android.model.FileActionEnum;
import com.openfarmanager.android.model.TaskStatusEnum;
import com.openfarmanager.android.utils.FileUtilsExt;
import com.openfarmanager.android.view.ToastNotification;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;

import static com.openfarmanager.android.controllers.FileSystemController.*;
import static com.openfarmanager.android.model.FileActionEnum.*;

public class MainPanel extends BasePanel {

    public static final int LEFT_PANEL = 0;
    public static final int RIGHT_PANEL = 1;

    private File mBaseDir;
    protected TextView mCurrentPathView;
    protected ListView mFileSystemList;
    protected ProgressBar mProgress;
    protected boolean mIsMultiSelectMode = false;
    protected List<File> mSelectedFiles = new ArrayList<File>();

    protected Handler mHandler;

    protected View mChangePathToLeft;
    protected View mChangePathToRight;

    protected View mAddToBookmarksLeft;
    protected View mAddToBookmarksRight;

    protected boolean mIsActivePanel;
    protected int mPanelLocation;

    protected ConfirmActionDialog mConfirmDialog;

    protected File mLastSelectedFile;

    private String mEncryptedArchivePassword;

    private FileActionEnum[] mActionsForDirectory = new FileActionEnum[] {COPY, MOVE, DELETE, CREATE_ARCHIVE};
    private FileActionEnum[] mActionsForFile = new FileActionEnum[] {COPY, MOVE, DELETE, EDIT, RENAME, FILE_OPEN_WITH, CREATE_ARCHIVE};

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        setupHandler();
        View view = inflater.inflate(R.layout.main_panel, container, false);
        mFileSystemList = (ListView) view.findViewById(android.R.id.list);
        mProgress = (ProgressBar) view.findViewById(R.id.loading);

        mFileSystemList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                if (mIsMultiSelectMode) {
                    File file = (File) adapterView.getItemAtPosition(i);
                    updateLongClickSelection(adapterView, file, false);
                    return;
                }
                mSelectedFiles.clear();
                File item = null;
                FileSystemFile file = null;
                if (!isRootDirectory()) {
                    if (i == 0) {
                        item = mBaseDir.getParentFile();
                    }
                }
                if (item == null) {
                    item = (FileSystemFile) adapterView.getItemAtPosition(i);
                }

                if (item instanceof FileSystemFile) {
                    file = (FileSystemFile) item;
                }

                if (file != null && file.isBookmark()) {
                    openDirectory(new File(file.getBookmark().getBookmarkPath()));
                    return;
                }

                if (item.isDirectory()) {
                    openDirectory(item);
                }
                if (item.isFile()) {
                    String mime = ArchiveUtils.getMimeType(item);
                    if (ArchiveUtils.isArchiveSupported(mime)) {
                        mHandler.sendMessage(mHandler.obtainMessage(OPEN_ARCHIVE, item));
                        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
                        if (adapter != null) {
                            adapter.clearSelectedFiles();
                        }
                    } else if (ArchiveUtils.isCompressionSupported(mime)) {
                        mHandler.sendMessage(mHandler.obtainMessage(OPEN_COMPRESSED_ARCHIVE, item));
                        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
                        if (adapter != null) {
                            adapter.clearSelectedFiles();
                        }
                    } else {
                        openFile(item);
                    }
                }
            }
        });

        mFileSystemList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                return onLongClick(adapterView, i);
            }
        });

        mFileSystemList.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                gainFocus();
                return false;
            }
        });

        mFileSystemList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        mCurrentPathView = (TextView) view.findViewById(R.id.current_path);
        mCurrentPathView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                final List<String> items = new ArrayList<String>(Arrays.asList(mBaseDir.getAbsolutePath().split("/")));
                if (items.size() == 0) {
                    return false;
                }
                items.set(0, "/");
                items.remove(items.size() - 1);

                if (Build.VERSION.SDK_INT > 10) {
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_selectable_list_item, items);
                    final ListPopupWindow select = new ListPopupWindow(getActivity());
                    select.setBackgroundDrawable(getResources().getDrawable(R.drawable.panel_path_background));
                    select.setAnchorView(view);
                    select.setAdapter(adapter);
                    select.setModal(true);
                    select.setWidth(400);
                    select.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
                            select.dismiss();
                            File f = new File(TextUtils.join("/", items.subList(0, pos + 1)));
                            if (f.exists() && f.canRead()) {
                                openDirectory(f);
                            }
                        }
                    });
                    select.show();
                } else {
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_singlechoice, items);
                    new AlertDialog.Builder(getActivity())
                            .setSingleChoiceItems(adapter, 0,
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int which) {
                                            dialog.dismiss();
                                            File f = new File(TextUtils.join("/", items.subList(0, which + 1)));
                                            if (f.exists() && f.canRead()) {
                                                openDirectory(f);
                                            }
                                        }
                                    })

                            .show();
                }

                return true;
            }
        });

        mChangePathToLeft = view.findViewById(R.id.change_folder_to_left);
        mChangePathToRight = view.findViewById(R.id.change_folder_to_right);

        mAddToBookmarksLeft = view.findViewById(R.id.add_to_bookmarks_left);
        mAddToBookmarksRight = view.findViewById(R.id.add_to_bookmarks_right);

        mChangePathToRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mHandler.sendMessage(mHandler.obtainMessage(CHANGE_PATH, RIGHT_PANEL));
            }
        });

        mChangePathToLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mHandler.sendMessage(mHandler.obtainMessage(CHANGE_PATH, LEFT_PANEL));
            }
        });

        mAddToBookmarksLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                gainFocus();
                mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.CREATE_BOOKMARK));
            }
        });

        mAddToBookmarksRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                gainFocus();
                mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.CREATE_BOOKMARK));
            }
        });

        postInitialization();
        setNavigationButtonsVisibility();

        return view;
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
    }

    protected boolean onLongClick(AdapterView<?> adapterView, int i) {
        File file = (File) adapterView.getItemAtPosition(i);
        if (!"..".equals(file.getName())) {
            mLastSelectedFile = file;
            updateLongClickSelection(adapterView, file, true);
            if (!((FileSystemFile) file).isVirtualDirectory()) {
                openFileActionMenu();
            }
        }
        return true;
    }

    @Override
    public void onStart() {
        super.onStart();
        openDirectory(mBaseDir != null ? mBaseDir : FileSystemScanner.sInstance.getRoot());
    }

    public void onResume() {
        super.onResume();
        // selected files need to be updated after application resumes
        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
        if (adapter != null && mSelectedFiles.size() > 0) {
            adapter.setSelectedFiles(mSelectedFiles);
            adapter.notifyDataSetChanged();
        }

        setIsActivePanel(mIsActivePanel);
    }

    public void gainFocus() {
        if (mHandler != null) {
            Message message = mHandler.obtainMessage();
            message.what = GAIN_FOCUS;
            message.arg1 = mPanelLocation;
            mHandler.sendMessage(message);
        }
    }

    private void updateLongClickSelection(AdapterView<?> adapterView, File file, boolean longClick) {
        if (((FileSystemFile) file).isVirtualDirectory()) {
            ToastNotification.makeText(App.sInstance.getApplicationContext(),
                    getString(R.string.error_virtual_directories_not_permitted), Toast.LENGTH_SHORT).show();
            return;
        }

        if("..".equals(file.getName())){
            return;
        }
        if (mSelectedFiles.contains(file) && !longClick) {
            mSelectedFiles.remove(file);
        } else {
            if (mSelectedFiles.contains(file)) {
                return;
            }
            mSelectedFiles.add(0, file);
        }
        ((FlatFileSystemAdapter) adapterView.getAdapter()).setSelectedFiles(mSelectedFiles);
        ((BaseAdapter) adapterView.getAdapter()).notifyDataSetChanged();
    }

    public void openFileActionMenu() {
        final FileActionDialog dialog = FileActionDialog.newInstance(getAvailableActions(),
                new FileActionDialog.OnActionSelectedListener() {
                    @Override
                    public void onActionSelected(FileActionEnum action) {
                        Message message = mHandler.obtainMessage();
                        message.what = FILE_ACTION;
                        message.obj = action;
                        mHandler.sendMessage(message);
                    }
        });
        try {
            dialog.show(fragmentManager(), "dialog");
        } catch (Exception e) {
        }
    }

    protected FragmentManager fragmentManager() throws Exception {
        Activity parent = getActivity();
        FragmentManager result = null;
        if (parent != null) {
            if (!parent.isFinishing()) {
                result = getActivity().getSupportFragmentManager();
            }
        } else {
            result = getFragmentManager();
        }
        if(result==null){
            throw new NullPointerException();
        }
        return result;
    }

    protected FileActionEnum[] getAvailableActions() {
        boolean oneFileSelected = getSelectedFiles().size() == 1 && (mLastSelectedFile != null && mLastSelectedFile.isFile());

        FileActionEnum[] actions;

        if (getSelectedFiles().size() == 1 && mLastSelectedFile instanceof FileSystemFile) {
            FileSystemFile lastSelectedFile = (FileSystemFile) mLastSelectedFile;
            if (lastSelectedFile.isBookmark()) {
                actions = new FileActionEnum[1];
                //actions[0] = RENAME;
                actions[0] = DELETE;
                return actions;
            }
        }

        if (oneFileSelected) {
            boolean extractSupport = ArchiveUtils.isArchiveSupported(mLastSelectedFile) ||
                    ArchiveUtils.isCompressionSupported(mLastSelectedFile);
            if (extractSupport) {
                actions = new FileActionEnum[mActionsForFile.length + 1];
                System.arraycopy(mActionsForFile, 0, actions, 0, mActionsForFile.length);
                actions[mActionsForFile.length] = FileActionEnum.ARCHIVE_EXTRACT;
            } else {
                actions = mActionsForFile;
            }
        } else {
            actions = mActionsForDirectory;
        }
        return actions;
    }

    public void executeAction(FileActionEnum action, final MainPanel inactivePanel) {
        if (action == MOVE || action == COPY || action == ARCHIVE_EXTRACT) {
            if (inactivePanel == null) {
                ToastNotification.makeText(App.sInstance.getApplicationContext(),
                        getString(R.string.error_quick_view_operation_not_supported), Toast.LENGTH_SHORT).show();
                return;
            } else if (!inactivePanel.getCurrentDir().exists()) {
                ToastNotification.makeText(App.sInstance.getApplicationContext(),
                        getString(R.string.error_virtual_directories_not_permitted), Toast.LENGTH_SHORT).show();
                return;
            } else if (inactivePanel instanceof ArchivePanel) {
                ToastNotification.makeText(App.sInstance.getApplicationContext(),
                        getString(R.string.error_archive_operation_not_supported), Toast.LENGTH_SHORT).show();
                return;
            }
        }

        if (mSelectedFiles.size() == 0) { // no operations can be performed
            return;
        }

        if (inactivePanel == null && (action.equals(MOVE) || action.equals(RENAME) || action.equals(COPY))) {
            // something really weird.
            return;
        }

        switch (action) {
            case DELETE:
                delete(inactivePanel);
                break;
            case MOVE:
                move(inactivePanel, false);
                break;
            case COPY:
                copy(inactivePanel);
                break;
            case EDIT:
                openFile(mLastSelectedFile);
                break;
            case RENAME:
                move(inactivePanel, true);
                break;
            case FILE_OPEN_WITH:
                openAs(mLastSelectedFile);
                break;
            case ARCHIVE_EXTRACT:
                extractArchive(inactivePanel);
                break;
            case CREATE_ARCHIVE:
                createArchive(inactivePanel);
                break;
        }
    }

    public void move(final MainPanel inactivePanel, boolean forceRename) {
        boolean isTheSameFolders;
        isTheSameFolders = FileUtilsExt.isTheSameFolders(getSelectedFiles(), inactivePanel.getCurrentDir());
        final boolean rename = forceRename || isTheSameFolders && getSelectedFiles().size() == 1;

        try {
            ConfirmActionDialog.newInstance(FileActionEnum.MOVE, mMoveCommand, rename,
                    rename ? getSelectedFiles().get(0).getName() : inactivePanel.getCurrentDir().getAbsolutePath(), rename).
                    show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createBookmark(final MainPanel inactivePanel) {
        try {
            ConfirmActionDialog.newInstance(FileActionEnum.CREATE_BOOKMARK, mCreateBookmarkCommand, mBaseDir.getAbsolutePath(), false).
                    show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void delete(final MainPanel inactivePanel) {
        FileProxy fileProxy = getLastSelectedFile();
        AbstractCommand deleteCommand = (fileProxy != null && fileProxy.isBookmark()) ? mDeleteBookmarkCommand : mDeleteCommand;

        try {
            ConfirmActionDialog.newInstance(FileActionEnum.DELETE, deleteCommand, null, false).
                show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void createFile(final MainPanel inactivePanel) {
        try {
            ConfirmActionDialog.newInstance(FileActionEnum.NEW, mCreateNewCommand, null, false).
                show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void showSelectDialog() {
        try {
            ConfirmActionDialog.newInstance(FileActionEnum.SELECT, mSelectFilesCommand, null,
                    App.sInstance.getSharedPreferences("action_dialog", 0).getString("select_pattern", "*"), false).show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void showSearchDialog() {
        try {
            SearchActionDialog.newInstance(new SearchActionDialog.OnSearchConfirmedListener() {
                @Override
                public void onSearchConfirmed(String fileMask, String keyword, boolean isCaseSensitive, boolean isWholeWords) {
                    try {
                        SearchResult.newInstance(getCurrentDir(), fileMask, keyword, isCaseSensitive, isWholeWords, new SearchResult.SearchResultListener() {
                            @Override
                            public void onGotoFile(File file) {
                                setCurrentDir(file.isDirectory() ? file : file.getParentFile());
                                invalidate();
                            }

                            @Override
                            public void onViewFile(File file) {
                                if (file.isDirectory()) {
                                    setCurrentDir(file);
                                    invalidate();
                                } else {
                                    openFile(file);
                                }
                            }

                            @Override
                            public void onResetSearch() {
                                showSearchDialog();
                            }
                        }).show(fragmentManager(), "searchResult");
                    } catch (Exception e) {
                    }
                }
            }).show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void copy(final MainPanel inactivePanel) {
        if (FileUtilsExt.isTheSameFolders(getSelectedFiles(), inactivePanel.getCurrentDir())) { // no need to copy.
            return;
        }
        mConfirmDialog = ConfirmActionDialog.newInstance(FileActionEnum.COPY, mCopyCommand,
                inactivePanel.getCurrentDir().getAbsolutePath(), false);
        try {
            mConfirmDialog.show(fragmentManager(), "confirmDialog");
        } catch (Exception e) {
        }
    }

    public void extractArchive(final MainPanel inactivePanel) {
        String extractFileName = mLastSelectedFile.getName();
        try {
            extractFileName = mLastSelectedFile.getName().split("\\.")[0];
        } catch (Exception ignore) { }
        String defaultPath = inactivePanel.getCurrentDir().getAbsolutePath();
        if (!defaultPath.endsWith(File.separator)) {
            defaultPath += File.separator;
        }
        defaultPath += extractFileName;

        final boolean isCompressed = ArchiveUtils.isCompressionSupported(mLastSelectedFile);

        try {
            ConfirmActionDialog.newInstance(FileActionEnum.ARCHIVE_EXTRACT, mExtractArchiveCommand,
                    isCompressed, defaultPath, false).show(fragmentManager(), "mConfirmDialog");
        } catch (Exception e) {
        }
    }

    public void createArchive(final MainPanel inactivePanel) {
        try {
            CreateArchiveDialog.newInstance(mCreateArchiveCommand,
                    FilenameUtils.removeExtension(mSelectedFiles.get(0).getName())).show(fragmentManager(), "mConfirmDialog");
        } catch (Exception e) {
        }
    }

    protected void invalidatePanels(MainPanel inactivePanel) {
        getSelectedFiles().clear();
        invalidate();
        // inactivePanel may be null when 'quick view' is opened.
        if (inactivePanel != null) {
            inactivePanel.invalidate();
        }
    }

    public void restoreState(String currentPath, boolean isActive) {
        File currentFile = new File(currentPath);
        setCurrentDir(currentFile);
        openDirectory(currentFile);
        setIsActivePanel(isActive);
    }

    public void invalidate() {
        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
        adapter.setSelectedFiles(mSelectedFiles);
        adapter.setBaseDir(mBaseDir);
        adapter.notifyDataSetChanged();
    }

    private void openFile(File item) {
        mHandler.sendMessage(mHandler.obtainMessage(FILE_OPEN, item.getAbsoluteFile()));
    }

    private void openAs(File item) {
        mHandler.sendMessage(mHandler.obtainMessage(OPEN_WITH, item.getAbsoluteFile()));
    }

    public void setIsMultiSelectMode(boolean value) {
        mIsMultiSelectMode = value;
    }

    public void switchMultiSelectMode() {
        mIsMultiSelectMode = !mIsMultiSelectMode;
    }

    public void setupHandler() {
        if (App.sInstance.getFileSystemController() != null) {
            mHandler = App.sInstance.getFileSystemController().getPanelHandler();
        }
    }

    public void setHandler(Handler handler) {
        mHandler = handler;
    }

    public FileProxy getLastSelectedFile() {
        return mLastSelectedFile instanceof FileProxy ? (FileProxy) mLastSelectedFile : null;
    }

    public List<File> getSelectedFiles() {
        if (mSelectedFiles.size() == 0 && mFileSystemList != null && mFileSystemList.getSelectedItem() != null) {
            mSelectedFiles.add((File) mFileSystemList.getSelectedItem());
        }
        return mSelectedFiles;
    }

    // TODO: for list of files use always Set instead of List (to avoid duplicated files).
    public Set<File> getAllFiles() {
        LinkedHashSet<File> allFiles = new LinkedHashSet<File>();
        try {
            Collections.addAll(allFiles, mBaseDir.listFiles());
        } catch (Exception ignore) {}
        return allFiles;
    }

    public File getCurrentDir() {
        return mBaseDir;
    }

    public void setCurrentDir(File dir) {
        mBaseDir = dir;
    }

    public boolean isActive() {
        return mIsActivePanel;
    }

    public void setIsActivePanel(final boolean active) {
        if (!mIsInitialized) {
            addToPendingList(new Runnable() {
                @Override
                public void run() {
                    setIsActivePanel(active);
                }
            });
            return;
        }

        mIsActivePanel = active;
        if (mCurrentPathView != null) {
            mCurrentPathView.setSelected(mIsActivePanel);
        }
        if (active && mFileSystemList != null) {
            mFileSystemList.requestFocus();
        }
    }

    public int getPanelLocation() {
        return mPanelLocation;
    }

    public void setPanelLocation(int location) {
        mPanelLocation = location;
        setNavigationButtonsVisibility();
    }

    public void setNavigationButtonsVisibility() {
        setNavigationButtonsVisibility(false);
    }

    public void forceHideNavigationButtons() {
        setNavigationButtonsVisibility(true);
    }

    private void setNavigationButtonsVisibility(final boolean forceHide) {
        if (!mIsInitialized) {
            addToPendingList(new Runnable() {
                @Override
                public void run() {
                    setNavigationButtonsVisibility(forceHide);
                }
            });
            return;
        }

        boolean isCopyFolderSupported = isCopyFolderSupported();
        mChangePathToLeft.setVisibility(!forceHide && isCopyFolderSupported && mPanelLocation == LEFT_PANEL ? View.VISIBLE : View.GONE);
        mChangePathToRight.setVisibility(!forceHide && isCopyFolderSupported && mPanelLocation == RIGHT_PANEL ? View.VISIBLE : View.GONE);

        mAddToBookmarksLeft.setVisibility(!forceHide && isCopyFolderSupported && mPanelLocation == LEFT_PANEL ? View.VISIBLE : View.GONE);
        mAddToBookmarksRight.setVisibility(!forceHide && isCopyFolderSupported && mPanelLocation == RIGHT_PANEL ? View.VISIBLE : View.GONE);
    }

    public boolean isRootDirectory() {
        if (App.sInstance.getSettings().isSDCardRoot()) {
            return mBaseDir.getAbsolutePath().equals(Settings.sSdPath);
        }
        return mBaseDir.getAbsolutePath().equals("/");
    }

    /**
     * Is 'move to folder' supported - buttons near the path to change path of inactive panel.
     * Must be ovveriden for subclasses.
     *
     * @return <code>true</code>
     */
    protected boolean isCopyFolderSupported() {
        return true;
    }

    public void openDirectory(final File directory) {

        if (!mIsInitialized) {
            addToPendingList(new Runnable() {
                @Override
                public void run() {
                    openDirectory(directory);
                }
            });
            return;
        }

        File oldDir = mBaseDir;
        mBaseDir = directory.getAbsoluteFile();
        mCurrentPathView.setText(mBaseDir.getAbsolutePath());
        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
        if (adapter == null) {
            mFileSystemList.setAdapter(new FlatFileSystemAdapter(mBaseDir));
        } else {
            sendEmptyMessage(FILTER_RESET);
            adapter.resetFilter();
            adapter.setBaseDir(mBaseDir);
            adapter.notifyDataSetChanged();
            mFileSystemList.setSelection(0);
            sendEmptyMessage(DIRECTORY_CHANGED);
        }
        if(adapter != null && oldDir != null){
            mFileSystemList.setSelection(adapter.getItemPosition(oldDir));
        }
    }

    private void sendEmptyMessage(int message) {
        if (mHandler != null) {
            mHandler.sendEmptyMessage(message);
        }
    }

    public void select(String pattern, boolean inverseSelection) {
        FileFilter select = new WildcardFileFilter(pattern);
        File[] contents = mBaseDir.listFiles(select);

        mSelectedFiles.clear();
        if (contents != null) {
            if (inverseSelection) {
                File[] allFiles = mBaseDir.listFiles();
                List selection = Arrays.asList(contents);
                for (File file : allFiles) {
                    if (!selection.contains(file)) {
                        mSelectedFiles.add(file);
                    }
                }
            } else {
                mSelectedFiles.addAll(Arrays.asList(contents));
            }
        }
        FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
        adapter.setSelectedFiles(mSelectedFiles);
        adapter.notifyDataSetChanged();
    }

    public void addSelectedFiles(LinkedHashSet<File> selectedFiles) {
        for (File file : selectedFiles) {
            if (!mSelectedFiles.contains(file)) {
                mSelectedFiles.add(file);
            }
        }

        final FlatFileSystemAdapter adapter = (FlatFileSystemAdapter) mFileSystemList.getAdapter();
        adapter.setSelectedFiles(mSelectedFiles);
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                adapter.notifyDataSetChanged();
            }
        });
    }

    public void navigateParent() {
        if (!isRootDirectory()) {
            // get parent file
            File parentFile = mBaseDir.getParentFile();
            // in case of parent file is null (for example, mBaseDir is already root. this shouldn't be happened)
            // use current dir.
            openDirectory(parentFile == null ? mBaseDir : parentFile);
        }
    }

    /**
     * Post runnable command with handle if fragment is attached to activity.
     *
     * @param runnable task to pe executed.
     */
    protected void postIfAttached(Runnable runnable) {
        //if (isAdded()) {
            mHandler.post(runnable);
        //}
    }

    public void navigateRoot() {
        if (!isRootDirectory()) {
            openDirectory(new File(FileSystemScanner.ROOT));
        }
    }

    public void filter(String obj) {
        ((FlatFileSystemAdapter) mFileSystemList.getAdapter()).filter(obj);
    }

    protected void setIsLoading(boolean isLoading) {
        mProgress.setVisibility(isLoading ? View.VISIBLE : View.GONE);
        mFileSystemList.setVisibility(isLoading ? View.GONE : View.VISIBLE);
        mCurrentPathView.setVisibility(isLoading ? View.GONE : View.VISIBLE);
    }

    /**
     * To be overriden in sub classes.
     *
     * @return null
     */
    public ArchiveScanner.File getCurrentArchiveItem() {
        return null;
    }

    /**
     * To be overriden in sub classes.
     *
     * @return null
     */
    protected String getArchivePassword() {
        return mEncryptedArchivePassword;
    }

    protected AbstractCommand mCopyCommand = new AbstractCommand() {

        @Override
        public void execute(final Object ... args) {
            FileActionTask task = null;
            try {
                task = new CopyTask(fragmentManager(),
                        new FileActionTask.OnActionListener() {
                            @Override
                            public void onActionFinish(TaskStatusEnum status) {
                                if (status.equals(TaskStatusEnum.OK)) {
                                } else {
                                    try {
                                        ErrorDialog.newInstance(
                                                status.equals(TaskStatusEnum.CANCELED) ?
                                                        TaskStatusEnum.getErrorString(status) :
                                                        App.sInstance.getString(R.string.error_cannot_copy_files, args[1])).
                                                show(fragmentManager(), "errorDialog");
                                    } catch (Exception e) {
                                    }
                                }
                                invalidatePanels(((MainPanel) args[0]));
                            }
                        }, getSelectedFiles(), new File((String) args[1]));
            } catch (Exception e) {
            }
            task.execute();
        }
    };

    protected AbstractCommand mDeleteCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            FileActionTask task = null;
            try {
                task = new DeleteTask(fragmentManager(),
                        new FileActionTask.OnActionListener() {
                            @Override
                            public void onActionFinish(TaskStatusEnum status) {
                                if (status.equals(TaskStatusEnum.OK)) {
                                } else {
                                    try {
                                        ErrorDialog.newInstance(TaskStatusEnum.getErrorString(status)).show(fragmentManager(), "errorDialog");
                                    } catch (Exception e) {
                                    }
                                }
                                invalidatePanels((MainPanel) args[0]);
                            }
                        }, getSelectedFiles());
            } catch (Exception e) {
            }
            task.execute();
        }
    };

    protected AbstractCommand mDeleteBookmarkCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            Bookmark bookmark = ((FileProxy) mLastSelectedFile).getBookmark();
            App.sInstance.getBookmarkManager().deleteBookmark(bookmark);

            invalidatePanels((MainPanel) args[0]);
        }
    };

    protected AbstractCommand mCreateNewCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            boolean createDirectory = (Boolean) args[2];
            File destination = new File(getCurrentDir(), (String) args[1]);
            boolean result;
            try {
                result = createDirectory ? destination.mkdir() : destination.createNewFile();
            } catch (IOException e) {
                result = false;
            }

            if (!result) {
                try {
                    ErrorDialog.newInstance(App.sInstance.getString(R.string.error_cannot_create_file, (String) args[1])).show(fragmentManager(), "errorDialog");
                } catch (Exception e) {
                }
            }
            invalidatePanels((MainPanel) args[0]);
        }
    };

    protected AbstractCommand mSelectFilesCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            select((String) args[1], (Boolean) args[2]);
            App.sInstance.getSharedPreferences("action_dialog", 0).edit().
                    putString("select_pattern", (String) args[1]).commit();

        }
    };

    protected AbstractCommand mExtractArchiveCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            FileActionTask task = null;
            try {
                task = new ExtractArchiveTask(fragmentManager(),
                        new FileActionTask.OnActionListener() {
                            @Override
                            public void onActionFinish(TaskStatusEnum status) {
                                if (status == TaskStatusEnum.OK) {
                                } else if (status == TaskStatusEnum.ERROR_EXTRACTING_ARCHIVE_FILES_ENCRYPTION_PASSWORD_REQUIRED) {
                                    try {
                                        RequestPasswordDialog.newInstance(mRequestPasswordCommand, args).show(fragmentManager(), "confirmDialog");
                                    } catch (Exception e) {
                                    }
                                } else {
                                    try {
                                        ErrorDialog.newInstance(TaskStatusEnum.getErrorString(status)).show(fragmentManager(), "error");
                                    } catch (Exception e) {
                                    }
                                }
                                invalidatePanels((MainPanel) args[0]);
                            }
                        }, mLastSelectedFile, new File((String) args[1]), (Boolean) args[3], getArchivePassword(), getCurrentArchiveItem());
            } catch (Exception e) {
            }
            task.execute();
        }
    };

    protected AbstractCommand mMoveCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            if ((Boolean) args[3]) {
                TaskStatusEnum status = new RenameTask(mLastSelectedFile, (String) args[1]).execute();
                if (status == TaskStatusEnum.OK) {
                } else {
                    try {
                        ErrorDialog.newInstance(TaskStatusEnum.getErrorString(status)).show(fragmentManager(), "errorDialog");
                    } catch (Exception e) {
                    }
                }
                invalidatePanels((MainPanel) args[0]);
            } else {
                FileActionTask task = null;
                try {
                    task = new MoveTask(fragmentManager(),
                            new FileActionTask.OnActionListener() {
                                @Override
                                public void onActionFinish(TaskStatusEnum status) {
                                    invalidatePanels((MainPanel) args[0]);
                                }
                            }, getSelectedFiles(), ((MainPanel) args[0]).getCurrentDir(), (String) args[1]);
                } catch (Exception e) {
                }
                task.execute();
            }
        }
    };

    protected AbstractCommand mCreateBookmarkCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            TaskStatusEnum status = App.sInstance.getBookmarkManager().createBookmark((String) args[1], (String) args[3]);

            if (status != TaskStatusEnum.OK) {
                try {
                    ErrorDialog.newInstance(TaskStatusEnum.getErrorString(status)).show(fragmentManager(), "errorDialog");
                } catch (Exception e) {
                }
            } else {
                ToastNotification.makeText(App.sInstance.getApplicationContext(),
                        getString(R.string.bookmark_created), Toast.LENGTH_SHORT).show();
            }

            invalidatePanels((MainPanel) args[0]);
        }
    };

    protected AbstractCommand mCreateArchiveCommand = new AbstractCommand() {
        @Override
        public void execute(final Object... args) {
            String currentPath = getCurrentDir().getAbsolutePath();
            if (!currentPath.endsWith(File.separator)) {
                currentPath += File.separator;
            }

            FileActionTask task = null;
            try {
                task = new CreateArchiveTask(fragmentManager(),
                        new FileActionTask.OnActionListener() {
                            @Override
                            public void onActionFinish(TaskStatusEnum status) {
                                if (status.equals(TaskStatusEnum.OK)) {
                                } else {
                                    try {
                                        ErrorDialog.newInstance(TaskStatusEnum.getErrorString(status)).show(fragmentManager(), "error");
                                    } catch (Exception e) {
                                    }
                                }
                                invalidatePanels((MainPanel) args[0]);
                            }
                        }, mSelectedFiles, currentPath + args[1],
                            (ArchiveUtils.ArchiveType) args[2],
                        (Boolean) args[3], (ArchiveUtils.CompressionEnum) args[4]);
            } catch (Exception e) {
            }
            task.execute();
        }
    };

    protected CancelableCommand mRequestPasswordCommand = new CancelableCommand() {

        @Override
        public void execute(final Object... args) {
            mEncryptedArchivePassword = (String) args[0];
            mExtractArchiveCommand.execute((args.length > 1) ? (Object[]) args[1] : null);
            mEncryptedArchivePassword = null;
        }

        @Override
        public void cancel() {

        }
    };

}